/* Copyright (C) 2003-2005 by Peter Eastman

   This program is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
   Foundation; either version 2 of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but WITHOUT ANY 
   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
   PARTICULAR PURPOSE.  See the GNU General Public License for more details. */

package artofillusion;

import artofillusion.math.*;
import artofillusion.object.*;
import artofillusion.ui.*;
import buoy.event.*;
import buoy.widget.*;
import java.awt.*;

/** BevelExtrudeTool is an EditingTool used for beveling and extruding TriangleMesh objects. */

public class BevelExtrudeTool extends EditingTool
{
  private boolean selected[], noSelection, separateFaces;
  private static Image icon, selectedIcon;
  private TriangleMesh origMesh;
  private TriMeshBeveler beveler;
  private Point clickPoint;
  private double width, height;
  private MeshEditController controller;
  
  public BevelExtrudeTool(EditingWindow fr, MeshEditController controller)
  {
    super(fr);
    this.controller = controller;
    if (icon == null)
      icon = loadImage("bevel.gif");
    if (selectedIcon == null)
      selectedIcon = loadImage("selected/bevel.gif");
  }
  
  /** Record the current selection. */
  
  private void recordSelection()
  {
    selected = controller.getSelection();
    noSelection = false;
    for (int i = 0; i < selected.length; i++)
      if (selected[i])
        return;
    noSelection = true;
  }

  public void activate()
  {
    super.activate();
    recordSelection();
    if (noSelection)
      theWindow.setHelpText(Translate.text("bevelExtrudeTool.errorText"));
    else
      theWindow.setHelpText(Translate.text("bevelExtrudeTool.helpText"));
  }

  public int whichClicks()
  {
    return ALL_CLICKS;
  }

  public Image getIcon()
  {
    return icon;
  }

  public Image getSelectedIcon()
  {
    return selectedIcon;
  }

  public String getToolTipText()
  {
    return Translate.text("bevelExtrudeTool.tipText");
  }
  
  public void mousePressed(WidgetMouseEvent e, ViewerCanvas view)
  {
    recordSelection();
    if (noSelection)
      return;
    TriMeshViewer mv = (TriMeshViewer) view;
    selected = controller.getSelection();
    TriangleMesh mesh = (TriangleMesh) controller.getObject().object;
    origMesh = (TriangleMesh) mesh.duplicate();
    int selectMode = controller.getSelectionMode();
    int mode;
    if (selectMode == TriMeshEditorWindow.POINT_MODE)
      mode = TriMeshBeveler.BEVEL_VERTICES;
    else if (selectMode == TriMeshEditorWindow.EDGE_MODE)
      mode = TriMeshBeveler.BEVEL_EDGES;
    else
      mode = (separateFaces ? TriMeshBeveler.BEVEL_FACES : TriMeshBeveler.BEVEL_FACE_GROUPS);
    beveler = new TriMeshBeveler(origMesh, selected, mode);
    clickPoint = e.getPoint();
  }
  
  public void mouseDragged(WidgetMouseEvent e, ViewerCanvas view)
  {
    if (noSelection)
      return;
    TriMeshViewer mv = (TriMeshViewer) view;
    TriangleMesh mesh = (TriangleMesh) controller.getObject().object;
    Camera cam = view.getCamera();
    Point dragPoint = e.getPoint();
    
    // Determine the bevel width and extrude height.
    
    Vec3 dragVec = cam.convertScreenToWorld(dragPoint, cam.getDistToScreen()).minus(cam.convertScreenToWorld(clickPoint, cam.getDistToScreen()));
    width = 0.5*dragVec.x;
    height = dragVec.y;
    width = (dragPoint.x-clickPoint.x)/cam.getScale();
    height = (clickPoint.y-dragPoint.y)/cam.getScale();
    if (controller.getSelectionMode() == TriMeshEditorWindow.FACE_MODE)
    {
      if (e.isShiftDown())
      {
        if (Math.abs(width) > Math.abs(height))
          height = 0.0;
        else
          width = 0.0;
      }
    }
    else
    {
      if (e.isShiftDown())
        height = 0.0;
      if (width < 0.0)
        width = 0.0;
    }
    
    // Update the mesh and redisplay.
    
    mesh.copyObject(beveler.bevelMesh(height, width));
    controller.setMesh(mesh);
    controller.setSelection(beveler.getNewSelection());
    theWindow.setHelpText(Translate.text("bevelExtrudeTool.dragText", new Double(width), new Double(height)));
  }

  public void mouseReleased(WidgetMouseEvent e, ViewerCanvas view)
  {
    if (noSelection || (width == 0.0 && height == 0.0))
      return;
    TriMeshViewer mv = (TriMeshViewer) view;
    TriangleMesh mesh = (TriangleMesh) controller.getObject().object;
    theWindow.setUndoRecord(new UndoRecord(theWindow, false, UndoRecord.COPY_OBJECT, new Object [] {mesh, origMesh}));
    controller.objectChanged();
    theWindow.updateImage();
    theWindow.setHelpText(Translate.text("bevelExtrudeTool.helpText"));
  }

  public void iconDoubleClicked()
  {
    BComboBox c = new BComboBox(new String [] {
      Translate.text("selectionAsWhole"),
      Translate.text("individualFaces")
    });
    c.setSelectedIndex(separateFaces ? 1 : 0);
    ComponentsDialog dlg = new ComponentsDialog(theFrame, Translate.text("applyExtrudeTo"),
        new Widget [] {c}, new String [] {null});
    if (dlg.clickedOk())
      separateFaces = (c.getSelectedIndex() == 1);
  }
}
